// Copyright 2021 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package types

import (
	"fmt"
	"testing"
	"time"

	"github.com/stretchr/testify/require"
)

var dayInMonth []int = []int{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

func TestDate(t *testing.T) {
	fmt.Println(DateFromCalendar(1215, 6, 15).Calendar(true))
	fmt.Println(DateFromCalendar(1776, 7, 4).Calendar(true))
	fmt.Println(DateFromCalendar(1989, 4, 26).Calendar(true))
	fmt.Println(DateFromCalendar(2019, 6, 9).Calendar(true))

	for i := 1; i <= 3000; i++ {
		for j := 1; j <= len(dayInMonth); j++ {
			for k := 1; k < days(i, j); k++ {
				tsys := time.Date(i, time.Month(j), k, 0, 0, 0, 0, time.UTC)
				y, m, d := tsys.Date()
				yw, w := tsys.ISOWeek()
				wd := tsys.Weekday()

				t := DateFromCalendar(int32(i), uint8(j), uint8(k))
				y1, m1, d1, _ := t.Calendar(true)
				yw1, w1 := t.WeekOfYear()
				wd1 := t.DayOfWeek()

				if y != int(y1) || m != time.Month(m1) || d != int(d1) || yw != int(yw1) || w != int(w1) || wd != time.Weekday(wd1) {
					fmt.Printf("=== %v %v %v", i, j, k)
				}
			}
		}
	}
}

func days(year, mon int) int {
	if mon == 2 && (year%4 == 0 && (year%100 != 0 || year%400 == 0)) {
		return 29
	} else {
		return dayInMonth[mon-1]
	}
}

func TestDatetime(t *testing.T) {
	dt := DatetimeFromClock(2021, 8, 13, 17, 55, 34, 0)
	fmt.Println(dt.ToDate().Calendar(true))
	fmt.Println(dt.Clock())

	dt = Now(time.UTC)
	fmt.Println(dt.ToDate().Calendar(true))
	fmt.Println(dt.Clock())

	loc, _ := time.LoadLocation("America/Los_Angeles")
	dt = Now(loc)
	fmt.Println(dt.ToDate().Calendar(true))
	fmt.Println(dt.Clock())
}

func TestAddDatetime(t *testing.T) {
	addDateTimeTbl := []struct {
		Input              string
		InputIntervalNum   string
		InputIntervalTypes IntervalType
		expect             string
		success            bool
	}{
		{"2022-01-31 00:00:00", "1", MicroSecond, "2022-01-31 00:00:00.000001", true},
		{"2022-01-31 00:00:00.000001", "1", MicroSecond, "2022-01-31 00:00:00.000002", true},
		{"2022-01-31 00:00:00.000001", "-1", MicroSecond, "2022-01-31 00:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Second, "2022-01-31 00:00:01.000000", true},
		{"2022-01-31 00:00:00", "1", Minute, "2022-01-31 00:01:00.000000", true},
		{"2022-01-31 00:00:00", "1", Hour, "2022-01-31 01:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Day, "2022-02-01 00:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Week, "2022-02-07 00:00:00.000000", true},
		{"2022-01-01 00:00:00", "1", Month, "2022-02-01 00:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Month, "2022-02-28 00:00:00.000000", true},
		{"2022-01-01 00:00:00", "1", Quarter, "2022-04-01 00:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Quarter, "2022-04-30 00:00:00.000000", true},
		{"2022-01-01 00:00:00", "1", Year, "2023-01-01 00:00:00.000000", true},
		{"2020-02-29 00:00:00", "1", Year, "2021-02-28 00:00:00.000000", true},

		{"2022-01-01 00:00:00", "1.1", Second_MicroSecond, "2022-01-01 00:00:01.100000", true},
		{"2022-01-01 00:00:00", "1:1.1", Minute_MicroSecond, "2022-01-01 00:01:01.100000", true},
		{"2022-01-01 00:00:00", "1:1", Minute_Second, "2022-01-01 00:01:01.000000", true},
		{"2022-01-01 00:00:00", "1:1:1.1", Hour_MicroSecond, "2022-01-01 01:01:01.100000", true},
		{"2022-01-01 00:00:00", "1:1:1", Hour_Second, "2022-01-01 01:01:01.000000", true},
		{"2022-01-01 00:00:00", "1:1", Hour_Minute, "2022-01-01 01:01:00.000000", true},
		{"2022-01-01 00:00:00", "1 1:1:1.1", Day_MicroSecond, "2022-01-02 01:01:01.100000", true},
		{"2022-01-01 00:00:00", "1 1:1:1", Day_Second, "2022-01-02 01:01:01.000000", true},
		{"2022-01-01 00:00:00", "1 1:1", Day_Minute, "2022-01-02 01:01:00.000000", true},
		{"2022-01-01 00:00:00", "1 1", Day_Hour, "2022-01-02 01:00:00.000000", true},
		{"2022-01-01 00:00:00", "1-1", Year_Month, "2023-02-01 00:00:00.000000", true},
		{"2022-02-01 00:00:00", "-1-1", Year_Month, "2021-01-01 00:00:00.000000", true},

		{"2022-01-31 00:00:00", "1-1", Year_Month, "2023-02-28 00:00:00.000000", true},

		{"2020-12-31 23:59:59", "1", Second, "2021-01-01 00:00:00.000000", true},
		{"2100-12-31 23:59:59", "1:1", Minute_Second, "2101-01-01 00:01:00.000000", true},
		{"1992-12-31 23:59:59.000002", "1.999999", Second_MicroSecond, "1993-01-01 00:00:01.000001", true},
		{"1992-12-31 23:59:59.1", "1.1", Second_MicroSecond, "1993-01-01 00:00:00.200000", true},
		{"2022-01-31 00:00:00.1", "100000", Month, "0001-01-01 00:00:00.000000", false},
		{"2022-01-31 00:00:00.999999", "1", MicroSecond, "2022-01-31 00:00:01.000000", true},
		{"2022-01-31 00:00:00.888888", "1", MicroSecond, "2022-01-31 00:00:00.888889", true},
	}
	for _, test := range addDateTimeTbl {
		ret, rettype, _ := NormalizeInterval(test.InputIntervalNum, test.InputIntervalTypes)
		d, err := ParseDatetime(test.Input, 6)
		require.Equal(t, err, nil)
		d, b := d.AddInterval(ret, rettype, DateTimeType)
		require.Equal(t, d.String2(6), test.expect)
		require.Equal(t, b, test.success)

	}
}

func TestSubDateTime(t *testing.T) {
	subDateTimeTbl := []struct {
		Input              string
		InputIntervalNum   string
		InputIntervalTypes IntervalType
		expect             string
		success            bool
	}{
		{"2022-01-31 00:00:00", "1", MicroSecond, "2022-01-30 23:59:59.999999", true},
		{"2022-01-31 00:00:00.000001", "1", MicroSecond, "2022-01-31 00:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Second, "2022-01-30 23:59:59.000000", true},
		{"2022-01-31 00:00:00", "1", Minute, "2022-01-30 23:59:00.000000", true},
		{"2022-01-31 00:00:00", "1", Hour, "2022-01-30 23:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Day, "2022-01-30 00:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Week, "2022-01-24 00:00:00.000000", true},
		{"2022-01-01 00:00:00", "1", Month, "2021-12-01 00:00:00.000000", true},
		{"2022-03-31 00:00:00", "1", Month, "2022-02-28 00:00:00.000000", true},
		{"2022-01-01 00:00:00", "1", Quarter, "2021-10-01 00:00:00.000000", true},
		{"2022-01-31 00:00:00", "1", Quarter, "2021-10-31 00:00:00.000000", true},
		{"2022-01-01 00:00:00", "1", Year, "2021-01-01 00:00:00.000000", true},
		{"2022-01-01 00:00:00", "-1", Year, "2023-01-01 00:00:00.000000", true},
		{"2020-02-29 00:00:00", "1", Year, "2019-02-28 00:00:00.000000", true},

		{"2022-01-01 00:00:00", "1.1", Second_MicroSecond, "2021-12-31 23:59:58.900000", true},
		{"2022-01-01 00:00:00", "-1.1", Second_MicroSecond, "2022-01-01 00:00:01.100000", true},
		{"2022-01-01 00:00:00", "1:1.1", Minute_MicroSecond, "2021-12-31 23:58:58.900000", true},
		{"2022-01-01 00:00:00", "1:1", Minute_Second, "2021-12-31 23:58:59.000000", true},
		{"2022-01-01 00:00:00", "1:1:1.1", Hour_MicroSecond, "2021-12-31 22:58:58.900000", true},
		{"2022-01-01 00:00:00", "1:1:1", Hour_Second, "2021-12-31 22:58:59.000000", true},
		{"2022-01-01 00:00:00", "1:1", Hour_Minute, "2021-12-31 22:59:00.000000", true},
		{"2022-01-01 00:00:00", "1 1:1:1.1", Day_MicroSecond, "2021-12-30 22:58:58.900000", true},
		{"2022-01-01 00:00:00", "1 1:1:1", Day_Second, "2021-12-30 22:58:59.000000", true},
		{"2022-01-01 00:00:00", "1 1:1", Day_Minute, "2021-12-30 22:59:00.000000", true},
		{"2022-01-01 00:00:00", "1 1", Day_Hour, "2021-12-30 23:00:00.000000", true},
		{"2022-01-01 00:00:00", "1-1", Year_Month, "2020-12-01 00:00:00.000000", true},
		{"2022-01-31 00:00:00.1", "1", Second, "2022-01-30 23:59:59.100000", true},
		{"2022-01-31 00:00:00.1", "100000", Month, "0001-01-01 00:00:00.000000", false},
	}
	for _, test := range subDateTimeTbl {
		ret, rettype, _ := NormalizeInterval(test.InputIntervalNum, test.InputIntervalTypes)
		d, err := ParseDatetime(test.Input, 6)
		require.Equal(t, err, nil)
		d, b := d.AddInterval(-ret, rettype, DateType)
		require.Equal(t, d.String2(6), test.expect)
		require.Equal(t, b, test.success)
	}
}

func TestParseDatetime(t *testing.T) {
	tests := []struct {
		name    string
		args    string
		want    string
		wantErr bool
	}{
		// 1. yyyy-mm-dd hh:mm:ss(.msec)
		{
			name: "yyyy-mm-dd hh:mm:ss",
			args: "1987-08-25 00:00:00.000000",
			want: "1987-08-25 00:00:00.000000",
		},
		{
			name: "yyyy-mm-dd hh:mm:ss",
			args: "1997-12-31 23:59:59",
			want: "1997-12-31 23:59:59.000000",
		},
		{
			name: "yyyy-mm-dd hh:mm:ss.sec",
			args: "1987-08-25 00:00:00.1",
			want: "1987-08-25 00:00:00.100000",
		},
		// 2. yyyymmddhhmmss(.msec)
		{
			name: "yyyymmddhhmmss",
			args: "19870825000000",
			want: "1987-08-25 00:00:00.000000",
		},
		{
			name: "yyyymmddhhmmss.sec",
			args: "19870825000000.5",
			want: "1987-08-25 00:00:00.500000",
		},
		// 3. out of range
		{
			name:    "out of range 1",
			args:    "1987-13-12 00:00:00",
			wantErr: true,
		},
		{
			name:    "out of range 2",
			args:    "1987-11-31 00:00:00",
			wantErr: true,
		},
		{
			name:    "out of range 3",
			args:    "1987-08-25 24:00:00",
			wantErr: true,
		},
		{
			name:    "out of range 4",
			args:    "1987-13-12 23:60:00",
			wantErr: true,
		},
		{
			name:    "out of range 5",
			args:    "1987-13-12 23:59:60",
			wantErr: true,
		},
		// 4. new format
		{
			name: "new format",
			args: "1987-2-12 11:20:03",
			want: "1987-02-12 11:20:03.000000",
		},
		{
			name: "new format",
			args: "1987-02-2 11:20:03",
			want: "1987-02-02 11:20:03.000000",
		},
		{
			name: "new format",
			args: "1987-12-12 1:20:03",
			want: "1987-12-12 01:20:03.000000",
		},
		{
			name: "new format",
			args: "1987-12-12 11:2:03",
			want: "1987-12-12 11:02:03.000000",
		},
		{
			name: "new format",
			args: "1987-12-12 11:02:3",
			want: "1987-12-12 11:02:03.000000",
		},
		{
			name: "bug",
			args: "1987-12-12 00:00:00.0000006",
			want: "1987-12-12 00:00:00.000001",
		},
		{
			name:    "wrong format",
			args:    "2022-01-02 00:00.00.000050",
			want:    "",
			wantErr: true,
		},
		// 5. colon separator format (MySQL compatible)
		{
			name: "colon separator yyyy:mm:dd hh:mm:ss",
			args: "2000:01:01 00:00:00",
			want: "2000-01-01 00:00:00.000000",
		},
		{
			name: "colon separator with microseconds",
			args: "2000:01:01 00:00:00.000001",
			want: "2000-01-01 00:00:00.000001",
		},
		{
			name: "colon separator with milliseconds",
			args: "2000:01:01 12:34:56.123456",
			want: "2000-01-01 12:34:56.123456",
		},
		// 6. ISO 8601 format (yyyy-mm-ddThh:mm:ss)
		{
			name: "ISO 8601 format yyyy-mm-ddThh:mm:ss",
			args: "2024-12-20T10:30:45",
			want: "2024-12-20 10:30:45.000000",
		},
		{
			name: "ISO 8601 format with microseconds",
			args: "2024-12-20T10:30:45.123456",
			want: "2024-12-20 10:30:45.123456",
		},
		{
			name: "ISO 8601 format with milliseconds",
			args: "2024-12-20T10:30:45.123",
			want: "2024-12-20 10:30:45.123000",
		},
		{
			name: "ISO 8601 format with single digit microseconds",
			args: "2024-12-20T10:30:45.1",
			want: "2024-12-20 10:30:45.100000",
		},
		{
			name: "ISO 8601 format midnight",
			args: "2024-12-20T00:00:00",
			want: "2024-12-20 00:00:00.000000",
		},
		{
			name: "ISO 8601 format end of day",
			args: "2024-12-20T23:59:59",
			want: "2024-12-20 23:59:59.000000",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ParseDatetime(tt.args, 6)
			if (err != nil) != tt.wantErr {
				t.Errorf("ParseDatetime() error = %v, wantErr %v", err, tt.wantErr)
				return
			}
			if err != nil && tt.wantErr {
				return
			}
			if got.String2(6) != tt.want {
				t.Errorf("ParseDatetime() got = %v, want %v", got.String2(6), tt.want)
			}
		})
	}
}

func TestUnix(t *testing.T) {
	for _, timestr := range []string{"1955-08-25 09:21:34", "2012-01-25 09:21:34"} {
		motime, _ := ParseDatetime(timestr, 6)
		motimeUnix := motime.UnixTimestamp(time.UTC)
		goLcoalTime, _ := time.ParseInLocation("2006-01-02 15:04:05", timestr, time.UTC)
		goUnix := goLcoalTime.Unix()

		require.Equal(t, motimeUnix, goUnix)

		parse_time := DatetimeFromUnix(time.UTC, motimeUnix)
		require.Equal(t, motime, parse_time)
	}
}

func TestDatetime_DayOfYear(t *testing.T) {
	cases := []struct {
		name    string
		datestr string
	}{
		{
			name:    "Test01",
			datestr: "1955-08-25 09:21:34",
		},
		{
			name:    "Test02",
			datestr: "2012-01-25 09:21:34",
		},
		{
			name:    "Test03",
			datestr: "1987-08-25 00:00:00",
		},
		{
			name:    "Test04",
			datestr: "2022-01-31 00:00:00",
		},
	}

	for _, c := range cases {
		t.Run(c.name, func(t *testing.T) {
			datetime, err := ParseDatetime(c.datestr, 6)
			if err != nil {
				t.Fatalf("parse datetime err %+v", err)
			}
			t.Logf("date string:%+v \n", c.datestr)
			year := datetime.DayOfYear()
			t.Logf("day of year:%+v \n", year)

			year2, week := datetime.WeekOfYear()
			t.Logf("weekofYear, year:%+v, week:%+v \n", year2, week)

			dayOfWeek := datetime.DayOfWeek()
			t.Logf("dayOfWeek:%+v \n", dayOfWeek)
		})
	}
}

func TestDatetime_TruncateToScale(t *testing.T) {
	// Test datetime with full microsecond precision: 2024-01-15 10:20:30.123456
	dt := DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123456)

	// Test scale 0 (seconds, no fractional part)
	truncated := dt.TruncateToScale(0)
	expected := DatetimeFromClock(2024, 1, 15, 10, 20, 30, 0)
	require.Equal(t, expected, truncated, "scale 0 should truncate to seconds")

	// Test scale 3 (milliseconds) - should truncate to .123000
	truncated = dt.TruncateToScale(3)
	expected = DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123000)
	require.Equal(t, expected, truncated, "scale 3 should truncate to milliseconds")

	// Test scale 6 (microseconds) - should not change
	truncated = dt.TruncateToScale(6)
	require.Equal(t, dt, truncated, "scale 6 should not change")

	// Test rounding up: .123500 with scale 3 should round to .124000
	dt2 := DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123500)
	truncated = dt2.TruncateToScale(3)
	expected = DatetimeFromClock(2024, 1, 15, 10, 20, 30, 124000)
	require.Equal(t, expected, truncated, "scale 3 should round .123500 up to .124000")

	// Test rounding up to next second: .999999 with scale 0 should round to next second
	dt3 := DatetimeFromClock(2024, 1, 15, 10, 20, 30, 999999)
	truncated = dt3.TruncateToScale(0)
	expected = DatetimeFromClock(2024, 1, 15, 10, 20, 31, 0)
	require.Equal(t, expected, truncated, "scale 0 should round .999999 to next second")

	// Test scale 1 (0.1 seconds): .156789 should round to .200000
	dt4 := DatetimeFromClock(2024, 1, 15, 10, 20, 30, 156789)
	truncated = dt4.TruncateToScale(1)
	expected = DatetimeFromClock(2024, 1, 15, 10, 20, 30, 200000)
	require.Equal(t, expected, truncated, "scale 1 should round .156789 to .200000")

	// Test scale 2 (0.01 seconds): .125678 should round to .130000
	dt5 := DatetimeFromClock(2024, 1, 15, 10, 20, 30, 125678)
	truncated = dt5.TruncateToScale(2)
	expected = DatetimeFromClock(2024, 1, 15, 10, 20, 30, 130000)
	require.Equal(t, expected, truncated, "scale 2 should round .125678 to .130000")

	// Test scale 4: .123456 should truncate to .123500 (rounds up from .123456)
	dt6 := DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123456)
	truncated = dt6.TruncateToScale(4)
	expected = DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123500)
	require.Equal(t, expected, truncated, "scale 4 should round .123456 to .123500")

	// Test scale 5: .123456 should truncate to .123460
	dt7 := DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123456)
	truncated = dt7.TruncateToScale(5)
	expected = DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123460)
	require.Equal(t, expected, truncated, "scale 5 should round .123456 to .123460")

	// Edge case: Test rounding at minute boundary
	dt8 := DatetimeFromClock(2024, 1, 15, 10, 20, 59, 999999)
	truncated = dt8.TruncateToScale(0)
	expected = DatetimeFromClock(2024, 1, 15, 10, 21, 0, 0)
	require.Equal(t, expected, truncated, "scale 0 should round 59.999999 to next minute")

	// Edge case: Test rounding at hour boundary
	dt9 := DatetimeFromClock(2024, 1, 15, 10, 59, 59, 999999)
	truncated = dt9.TruncateToScale(0)
	expected = DatetimeFromClock(2024, 1, 15, 11, 0, 0, 0)
	require.Equal(t, expected, truncated, "scale 0 should round to next hour")

	// Edge case: Test rounding at day boundary
	dt10 := DatetimeFromClock(2024, 1, 15, 23, 59, 59, 999999)
	truncated = dt10.TruncateToScale(0)
	expected = DatetimeFromClock(2024, 1, 16, 0, 0, 0, 0)
	require.Equal(t, expected, truncated, "scale 0 should round to next day")
}

// TestDatetime_String2_NoNewline tests that String2 output does not contain newline characters
// This test ensures the fix for the String2 formatting bug (removing newline from %06d\n)
func TestDatetime_String2_NoNewline(t *testing.T) {
	testCases := []struct {
		name     string
		datetime Datetime
		scale    int32
	}{
		{
			name:     "scale 0",
			datetime: DatetimeFromClock(2024, 1, 15, 10, 20, 30, 0),
			scale:    0,
		},
		{
			name:     "scale 1",
			datetime: DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123456),
			scale:    1,
		},
		{
			name:     "scale 3",
			datetime: DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123456),
			scale:    3,
		},
		{
			name:     "scale 6",
			datetime: DatetimeFromClock(2024, 1, 15, 10, 20, 30, 123456),
			scale:    6,
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			result := tc.datetime.String2(tc.scale)
			// Ensure no newline character in the output
			require.NotContains(t, result, "\n", "String2 output should not contain newline")
			require.NotContains(t, result, "\r", "String2 output should not contain carriage return")

			// Verify the format is correct
			if tc.scale > 0 {
				require.Contains(t, result, ".", "String2 with scale > 0 should contain decimal point")
			}
		})
	}
}

// TestDatetime_ToTime tests the ToTime method with various scales, including edge cases
// This test ensures that ToTime handles scale > 6 correctly without array bounds issues
func TestDatetime_ToTime(t *testing.T) {
	// Test datetime: 2007-12-31 23:59:59.123456
	dt := DatetimeFromClock(2007, 12, 31, 23, 59, 59, 123456)

	testCases := []struct {
		name     string
		datetime Datetime
		scale    int32
		expected string // Expected time string representation
	}{
		{
			name:     "scale 0 - seconds only",
			datetime: dt,
			scale:    0,
			expected: "23:59:59",
		},
		{
			name:     "scale 1 - 0.1 seconds",
			datetime: dt,
			scale:    1,
			expected: "23:59:59.1",
		},
		{
			name:     "scale 3 - milliseconds",
			datetime: dt,
			scale:    3,
			expected: "23:59:59.123",
		},
		{
			name:     "scale 6 - microseconds",
			datetime: dt,
			scale:    6,
			expected: "23:59:59.123456",
		},
		{
			name:     "scale 7 - should use scale 6 (no panic)",
			datetime: dt,
			scale:    7,
			expected: "23:59:59.1234560", // String2 now supports scale > 6 with padding
		},
		{
			name:     "scale 9 - should use scale 6 (no panic)",
			datetime: dt,
			scale:    9,
			expected: "23:59:59.123456000", // String2 now supports scale > 6 with padding
		},
		{
			name: "scale 9 with ADDTIME result - should not panic",
			// Simulate ADDTIME result with scale 9
			datetime: DatetimeFromClock(2008, 1, 2, 1, 1, 1, 1),
			scale:    9,
			expected: "01:01:01.000001000", // String2 now supports scale > 6 with padding
		},
	}

	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			// This should not panic even with scale > 6
			result := tc.datetime.ToTime(tc.scale)
			actual := result.String2(tc.scale)
			require.Equal(t, tc.expected, actual, "ToTime(%d) should produce correct time string", tc.scale)
		})
	}

	// Test the exact case that caused the panic: TIME(ADDTIME(...))
	// ADDTIME('12:30:45', '01:15:30') produces a datetime with scale 9
	time1, _ := ParseTime("12:30:45", 6)
	time2, _ := ParseTime("01:15:30", 6)
	// Simulate ADDTIME result: convert time to datetime and add
	dt1 := time1.ToDatetime(9) // This creates a datetime with scale 9
	dt2 := time2.ToDatetime(9)
	resultDt := Datetime(int64(dt1) + int64(dt2))
	// Convert back to TIME - this should not panic
	resultTime := resultDt.ToTime(9)
	require.Equal(t, "13:46:15.000000", resultTime.String2(6), "TIME(ADDTIME(...)) should work correctly")
}

// TestAddIntervalMicrosecond tests AddInterval with MicroSecond unit
// This test verifies the fix for TIMESTAMPADD(MICROSECOND, 1000000, DATE('2024-12-20'))
func TestAddIntervalMicrosecond(t *testing.T) {
	// Test case: DATE('2024-12-20') + 1000000 microseconds = 2024-12-20 00:00:01.000000
	date, _ := ParseDateCast("2024-12-20")
	dt := date.ToDatetime()

	// Add 1000000 microseconds (1 second)
	result, success := dt.AddInterval(1000000, MicroSecond, DateTimeType)
	require.True(t, success, "AddInterval should succeed for MicroSecond")
	require.NotEqual(t, Datetime(0), result, "Result should not be zero")

	// Verify the result is 2024-12-20 00:00:01.000000
	expected, _ := ParseDatetime("2024-12-20 00:00:01.000000", 6)
	require.Equal(t, expected, result, "DATE + 1000000 microseconds should equal 2024-12-20 00:00:01.000000")

	// Verify the string representation
	require.Equal(t, "2024-12-20 00:00:01.000000", result.String2(6), "String representation should match")

	// Test with different microsecond values
	testCases := []struct {
		microseconds int64
		expected     string
	}{
		{1000000, "2024-12-20 00:00:01.000000"}, // 1 second
		{500000, "2024-12-20 00:00:00.500000"},  // 0.5 seconds
		{123456, "2024-12-20 00:00:00.123456"},  // 123456 microseconds
		{2000000, "2024-12-20 00:00:02.000000"}, // 2 seconds
	}

	for _, tc := range testCases {
		result, success := dt.AddInterval(tc.microseconds, MicroSecond, DateTimeType)
		require.True(t, success, "AddInterval should succeed for %d microseconds", tc.microseconds)
		require.NotEqual(t, Datetime(0), result, "Result should not be zero for %d microseconds", tc.microseconds)
		require.Equal(t, tc.expected, result.String2(6), "Result should match expected for %d microseconds", tc.microseconds)
	}
}
